using M13.Utility;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;


#if UNITY_EDITOR
    public class VoxelModelGenerator : MonoBehaviour
    {
        public string modalName;
        public Texture2D texture;
        public Material material;

        public float realModalSize;

        public float realModalThickness;

        public Vector3 origin;

        public string savePath;

        GameObject _obj;
        MeshFilter _meshFilter;
        MeshRenderer _meshRenderer;
        Vector3Int[] _neighbor = new Vector3Int[4] { new Vector3Int(-1, 0), new Vector3Int(0, 1), new Vector3Int(1, 0), new Vector3Int(0, -1) };

        Mesh _mesh;

        [FormerlySerializedAs("_sizeTextureLength")]
        [Space(10)]
        [Header("私有变量")]
        [SerializeField] private int sizeTextureLength;
        [FormerlySerializedAs("_singleMeshSize")] [SerializeField] private float singleMeshSize;
        [SerializeField] private int alphaPxeilCount;
       
       
        [SerializeField] private List<Vector3> vertices = new List<Vector3>();
        [SerializeField] private List<Vector2> uv = new List<Vector2>();
        [SerializeField] private List<int> triangles = new List<int>();
        public void Generator()
        {
            alphaPxeilCount = 0;
            vertices.Clear();
            uv.Clear();
            triangles.Clear();

            if (texture.width != texture.height) Debug.LogWarning("尺寸不对");
            sizeTextureLength = texture.width;

            singleMeshSize = realModalSize / sizeTextureLength;

            _obj = new GameObject(modalName);


            int trianglesIndex = 0;

            if (texture != null && texture.isReadable)
            {
                for(int x = 0; x < sizeTextureLength; x++)
                {
                    for (int y = 0; y < sizeTextureLength; y++)
                    {
                        if (texture.GetPixel(x, y).a == 1f) alphaPxeilCount++;
                        else continue;
                        //????
                        vertices.Add((new Vector3(x, y, -realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x, y + 1, -realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x + 1, y + 1, -realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x + 1, y, -realModalThickness / 2f) * singleMeshSize) - origin);

                        uv.Add(new Vector2(x, y) / sizeTextureLength);
                        uv.Add(new Vector2(x, y + 1) / sizeTextureLength);
                        uv.Add(new Vector2(x + 1, y + 1) / sizeTextureLength);
                        uv.Add(new Vector2(x + 1, y) / sizeTextureLength);

                        triangles.Add(trianglesIndex);
                        triangles.Add(trianglesIndex + 1);
                        triangles.Add(trianglesIndex + 2);
                        triangles.Add(trianglesIndex + 0);
                        triangles.Add(trianglesIndex + 2);
                        triangles.Add(trianglesIndex + 3);

                        //????
                        vertices.Add((new Vector3(x + 1, y, realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x + 1, y + 1, realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x, y + 1, realModalThickness / 2f) * singleMeshSize) - origin);
                        vertices.Add((new Vector3(x, y, realModalThickness / 2f) * singleMeshSize) - origin);

                        uv.Add(new Vector2(x + 1, y) / sizeTextureLength);
                        uv.Add(new Vector2(x + 1, y + 1) / sizeTextureLength);
                        uv.Add(new Vector2(x, y + 1) / sizeTextureLength);
                        uv.Add(new Vector2(x, y) / sizeTextureLength);

                        triangles.Add(trianglesIndex + 4);
                        triangles.Add(trianglesIndex + 5);
                        triangles.Add(trianglesIndex + 6);
                        triangles.Add(trianglesIndex + 4);
                        triangles.Add(trianglesIndex + 6);
                        triangles.Add(trianglesIndex + 7);

                        for (int i = 0; i < _neighbor.Length; i++)
                        {
                            //???????
                            if (texture.GetPixel(_neighbor[i].x + x, _neighbor[i].y + y).a != 1f)
                            {
                                //???
                                if (i == 0)
                                {
                                    vertices.Add(new Vector3(x, y, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y + 1, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y + 1, -realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y, -realModalThickness / 2f) * singleMeshSize - origin);

                                    SetSideMesh(x, y, ref trianglesIndex);
                                }
                                else if (i == 1)
                                {
                                    vertices.Add(new Vector3(x, y + 1, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y + 1, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y + 1, -realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y + 1, -realModalThickness / 2f) * singleMeshSize - origin);

                                    SetSideMesh(x, y, ref trianglesIndex);
                                }
                                else if (i == 2)
                                {
                                    vertices.Add(new Vector3(x + 1, y + 1, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y, -realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y + 1, -realModalThickness / 2f) * singleMeshSize - origin);

                                    SetSideMesh(x, y, ref trianglesIndex);
                                }
                                else if (i == 3)
                                {
                                    vertices.Add(new Vector3(x + 1, y, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y, realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x, y, -realModalThickness / 2f) * singleMeshSize - origin);
                                    vertices.Add(new Vector3(x + 1, y, -realModalThickness / 2f) * singleMeshSize - origin);

                                    SetSideMesh(x, y, ref trianglesIndex);
                                }
                            }
                        }

                        trianglesIndex += 8;
                    }
                }
            }

            _obj.transform.position = new Vector3(0, 5, 0);
            _meshFilter = _obj.AddComponent<MeshFilter>();
            _meshRenderer = _obj.AddComponent<MeshRenderer>();
            _mesh = new Mesh();
            _mesh.vertices = vertices.ToArray();
            _mesh.uv = uv.ToArray();
            _mesh.triangles = triangles.ToArray();
            _mesh.RecalculateNormals();

            _meshFilter.mesh = _mesh;
            _meshRenderer.material = material;
        }

        private void SetSideMesh(int x, int y, ref int trianglesIndex)
        {
            uv.Add(new Vector2(x, y) / sizeTextureLength);
            uv.Add(new Vector2(x, y + 1) / sizeTextureLength);
            uv.Add(new Vector2(x + 1, y + 1) / sizeTextureLength);
            uv.Add(new Vector2(x + 1, y) / sizeTextureLength);

            triangles.Add(trianglesIndex + 8);
            triangles.Add(trianglesIndex + 9);
            triangles.Add(trianglesIndex + 10);
            triangles.Add(trianglesIndex + 8);
            triangles.Add(trianglesIndex + 10);
            triangles.Add(trianglesIndex + 11);

            trianglesIndex += 4;
        }

        public void ApplyRot()
        {
            Quaternion rotation = _obj.transform.rotation;

            _mesh = _meshFilter.sharedMesh;
            Vector3[] vs = _mesh.vertices;
            for(int i = 0; i < vs.Length; i++)
            {
                Vector3 v = rotation * vs[i];
                vs[i] = v;
            }
            _mesh.vertices = vs;
            _mesh.RecalculateNormals();
            _meshFilter.mesh = _mesh;
            _obj.transform.rotation = Quaternion.Euler(0, 0, 0);
        }

        
        public void SaveMeshToObj()
        {
            StringBuilder sb = new StringBuilder();
            StringBuilder mtlSb = new StringBuilder();

            sb.AppendLine($"mtllib {modalName}.mtl");
            sb.AppendLine($"usemtl {material.name}");

            foreach (Vector3 v in _mesh.vertices)
            {
                sb.AppendLine($"v {v.x} {v.y} {v.z}");
            }

            foreach (Vector3 n in _mesh.normals)
            {
                sb.AppendLine($"vn {n.x} {n.y} {n.z}");
            }

            foreach (Vector2 uv in _mesh.uv)
            {
                sb.AppendLine($"vt {uv.x} {uv.y}");
            }

            for (int i = 0; i < _mesh.triangles.Length; i += 3)
            {
                sb.AppendLine($"usemtl {material.name}");
                sb.AppendLine($"f {triangles[i] + 1}/{triangles[i] + 1} {triangles[i + 1] + 1}/{triangles[i + 1] + 1} {triangles[i + 2] + 1}/{triangles[i + 2] + 1}");
            }

            

            if (material != null)
            {
                string materialName = material.name;
                sb.AppendLine($"usemtl {materialName}");

                mtlSb.AppendLine($"newmtl {materialName}");
                if (material.HasProperty("_Color"))
                {
                    Color color = material.color;
                    mtlSb.AppendLine($"Kd {color.r} {color.g} {color.b}");
                }
                if (material.HasProperty("_MainTex"))
                {
                    Texture texture = material.GetTexture("_MainTex");
                    if (texture != null)
                    {
                        string texturePath = UnityEditor.AssetDatabase.GetAssetPath(texture);
                        mtlSb.AppendLine($"map_Kd {texturePath}");
                    }
                }
            }
            string path = $"{Application.dataPath}/{savePath}/{modalName}.obj";
            File.WriteAllText(path, sb.ToString());
        }
    }
#endif

#if UNITY_EDITOR
[CustomEditor(typeof(VoxelModelGenerator))]
public class MapCreateEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        VoxelModelGenerator t = (VoxelModelGenerator)target;
        if (GUILayout.Button("创建网格"))
        {
            t.Generator();
        }

        if (GUILayout.Button("应用旋转"))
        {
            t.ApplyRot();
        }

        if (GUILayout.Button("保存模型"))
        {
            t.SaveMeshToObj();
        }

    }
}
#endif